home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Night Owl 8
/
Night Owl CD-ROM (NOPV8) (Night Owl Publisher) (1993).ISO
/
034a
/
aecur101.arj
/
CONTRIB
/
CURSES
/
SRC
/
KBBGTASK.C
< prev
next >
Wrap
C/C++ Source or Header
|
1990-03-08
|
6KB
|
248 lines
/*----------------------------------------------------------------------
*
* kbbgtask.c
*
* copyright (c) 1987,88,89,90 J. Alan Eldridge
*
* background tasking keyboard handler for Curses
*
* NOTES:
*
* look, folks, all this does is fake multitasking while
* the user is sitting thinking about what to type
*
* there are a maximum of MAX tasks in the queue, and each
* task must be a function that takes no args and whose
* return value can be ignored
*
* lastly, and most importantly, this thing relies on two basic
* concepts:
*
* 1. a user sits there without typing anyting, just
* thinking, quite a bit of the time, so DOS sits there are
* repeatedly polls the keyboard (twiddling its thumbs)
*
* 2. if i poll the keyboard myself, i can use some time to
* do some TRIVIAL (meaning FAST!!) tasks while said user
* is ruminating on what key to press next, thereby making
* more effective use of available CPU cycles
*
* example use of all this:
*
* int show_time_in_corner();
*
* addbgtask(show_time_in_corner,5); -- add a real time clock, priority 5
* so that whenever you're waiting, the time is updated onscreen
*
* now, whenever Curses reads a character, it will go through this
* routine kbgetc() and automagically run things for you! anytime
* you call getch() or wgetch() etc. you'll come here
*
* BUGS/WARNINGS:
*
* 1. a task (obviously!) can't do keyboard input (FIXED 1/90)
*
* 2. a task shouldn't mess with other tasks
*
* 3. task ids are assigned in numerical order, and are not reused,
* so you can't add more than 32k tasks in a single program run
* without risking weirdness (this limit really shouldn't be of
* any consequence, since if you add and kill that many tasks you
* probably are doing something else wrong that is worse, anyway)
*
* 4. a task should be a short, fast routine or else keyboard
* response will be degraded unacceptably
*
*----------------------------------------------------------------------
*/
#include "curses.h"
#define TASK_MAX 32
typedef void (*PFV)();
/*----------------------------------------------------------------------
*
* the task handler's private storage
*
* how many tasks, who is up next, and pointers
*
*----------------------------------------------------------------------
*/
struct tcb {
int id,pri,cnt;
PFV func;
};
static int taskcnt = 0, currtask = 0, nextid = 0;
static struct tcb tasktabl[TASK_MAX];
/*----------------------------------------------------------------------
*
* static findtask -- look up a task id in the table
*
*----------------------------------------------------------------------
*/
static int
findtask(id)
int id;
{
int i;
for (i = 0; i < taskcnt; i++)
if (tasktabl[i].id == id)
return i;
return -1;
}
/*----------------------------------------------------------------------
*
* getbgpri -- returns the priority of the task specified
*
* BUGS:
*
* since it returns -1 on error, there is no way to know if a
* task is invalid or just not running
*
*----------------------------------------------------------------------
*/
int
getbgpri(id)
int id;
{
int n = findtask(id);
return (n >= 0) ? tasktabl[n].pri : -1;
}
/*----------------------------------------------------------------------
*
* setbgpri -- given a task id, sets the priority
*
* a priority < 0 disables the task from running
*
*----------------------------------------------------------------------
*/
int
setbgpri(id, pri)
int id, pri;
{
int n = findtask(id);
if (n >= 0) {
tasktabl[n].pri = pri;
return 0;
}
return -1;
}
/*----------------------------------------------------------------------
*
* addbgtask -- queues up a task in the scheduler & executes it once
*
* returns the task id or -1 if error
*
*----------------------------------------------------------------------
*/
int
addbgtask(func, pri)
void (*func)();
int pri;
{
if (taskcnt < TASK_MAX) {
(*func)();
tasktabl[taskcnt].func = func;
tasktabl[taskcnt].pri = pri;
tasktabl[taskcnt].cnt = 0;
return tasktabl[taskcnt++].id = nextid++;
}
return -1;
}
/*----------------------------------------------------------------------
*
* rmvbgtask -- removes a task (unqueues it)
*
* returns the number of tasks remaining
*
*----------------------------------------------------------------------
*/
int
rmvbgtask(id)
int id;
{
int n = findtask(id);
if (n >= 0 && n < taskcnt) {
int i;
for (i = n; i < taskcnt - 1; i++)
tasktabl[i] = tasktabl[i+1];
if (currtask == n) {
if (currtask == taskcnt - 1)
currtask = 0;
} else if (currtask > n)
currtask--;
return --taskcnt;
}
return -1;
}
/*----------------------------------------------------------------------
*
* kbgetc -- poll the keyboard and multitask while waiting
* then return a character
*
* the static recursion flag lets a task do keyboard input
*
* this should really be reserved for things like error conditions
* because it is just not a clean way to do things in general
*
* if the key is ctl-backslash, clean up and exit (panic)
*
*----------------------------------------------------------------------
*/
static int recurse = 0;
int
kbgetc()
{
int c;
if (!recurse) {
recurse++;
while (!_kb_look()) {
if (taskcnt < 1)
continue;
if (tasktabl[currtask].cnt++ >= tasktabl[currtask].pri) {
if (tasktabl[currtask].pri >= 0)
(*(tasktabl[currtask].func))();
tasktabl[currtask].cnt = 0;
}
if (++currtask >= taskcnt)
currtask = 0;
}
recurse--;
}
c = _kb_getc();
if (c == K_CTL_BKSLASH) {
endwin();
exit(1);
}
return c;
}